﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

public interface ITCPSocketServer: ISocketServer
{
    void OnNewConnected(EndPoint endPoint,Socket connect);
}

public class TCPSocketServer : ServerSocket
{
    public ITCPSocketServer tcpServerListener;

    public override ISocketServer socketServerListenr => tcpServerListener;

    public override bool connected => m_Socket != null ? m_Socket.Connected : false;

    public virtual IPEndPoint ipEndPoint
    {
        get
        {
            try
            {
                return m_Socket != null ? (IPEndPoint)(m_Socket.RemoteEndPoint) : null;
            }
            catch (Exception e)
            {
                LogSocketException(e);
                return null;
            }
        }
    }

    public TCPSocketServer(IEncode encoder, IDecode decoder)
    {
        this.encoder = encoder;
        this.decoder = decoder;
        m_Buffer = new byte[TCPPacket.maxSendTotalOneTime];
    }

    public TCPSocketServer(ITCPSocketServer ITcpSocketServer,IEncode encoder, IDecode decoder)
    {
        this.encoder = encoder;
        this.decoder = decoder;
        this.tcpServerListener = ITcpSocketServer;
    }

    public TCPSocketServer(Socket connect)
    {
        this.m_Socket = connect;
    }
    public TCPSocketServer(Socket connect, IEncode encoder, IDecode decoder)
    {
        this.encoder = encoder;
        this.decoder = decoder;
        this.m_Socket = connect;
    }
    public override void Start(int port,int maxConnectCount)
    {
        var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
        IPAddress ip = IPAddress.Any;
        IPEndPoint iPEndPoint = new IPEndPoint(ip, port);
        socket.Bind(iPEndPoint);

        GameDebug.Log($"SocketServer Start Listen :{port}  maxConnectCount:{maxConnectCount}");

        socket.Listen(maxConnectCount);//最大连接数

        Thread listenThread = new Thread(Listen);
        listenThread.Start(socket);
    }

    protected void Listen(object so)
    {
        Socket socket = so as Socket;

        while (true)
        {
            GameDebug.Log($"等待连接:");
            Socket connect = socket.Accept();
            var ipConnected = connect.RemoteEndPoint;

            IPEndPoint iPEndPoint = (connect.RemoteEndPoint as IPEndPoint);
            GameDebug.Log($"连接上：{ipConnected}  address:{iPEndPoint.Address}  port:{iPEndPoint.Port}  ");

            //m_SocketConnect = connect;
            //OnNewConnected(connect);
            tcpServerListener?.OnNewConnected(iPEndPoint, connect);
        }
    }

    Action<Socket, string> m_OnConnectComplete;
    /// <summary>
    /// 连接
    /// </summary>
    /// <param name="address"></param>
    /// <param name="port"></param>
    public void BeginConnect(string address, int port, Action<Socket, string> onConnectComplete)
    {
        GameDebug.Log($"开始连接:{address}  port：{port}");

        m_OnConnectComplete = onConnectComplete;

        try
        {
            Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

            TryParseHost(address, out IPAddress iPAddress);

            SocketAsyncEventArgs socketEventArgs = new SocketAsyncEventArgs();
            socketEventArgs.RemoteEndPoint = new IPEndPoint(iPAddress, port);
            socketEventArgs.Completed += OnConnectCompleted;

            bool IOPending = socket.ConnectAsync(socketEventArgs);
            if (!IOPending)
            {
                GameDebug.LogShowy("I/O operation completed synchronously");
                
                //同布手动回调
                OnConnectCompleted(false, socketEventArgs);

                socketEventArgs.Completed -= OnConnectCompleted;
                socketEventArgs.Dispose();
            }
        }
        catch (Exception e)
        {
            m_OnConnectComplete?.Invoke(null, e.Message);

            LogSocketException(e);
        }
    }

    /// <summary>
    /// 连接完成
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="socketEventArgs"></param>
    void OnConnectCompleted(object sender, SocketAsyncEventArgs socketEventArgs)
    {
        m_Socket = socketEventArgs.ConnectSocket;

        if (m_Socket != null && m_Socket.Connected)
        {
            GameDebug.Log("连接成功");
            this.m_OnConnectComplete?.Invoke(socketEventArgs.ConnectSocket, "");

            // m_Socket = socketEventArgs.AcceptSocket;
            //BeginReceive();
        }
        else
        {
            GameDebug.Log("连接失败");

            this.m_OnConnectComplete?.Invoke(null, $"连接失败:{socketEventArgs.SocketError}");
            return;
        }

    }
    

    public override void BeginReceive()
    {
        if(m_Socket == null || !m_Socket.Connected)
        {
            this.Disconnect();
            return;
        }

        try
        {
            m_Socket.BeginReceive(m_Buffer, 0, m_Buffer.Length, SocketFlags.None, OnReceiveData, null);
        }
        catch (Exception ex)
        {
            GameDebug.LogError("接收异常: " + ex);

            this.Disconnect();
        }
    }
    
    void OnReceiveData(IAsyncResult result)
    {
        if (m_Socket == null)
        {
            GameDebug.Log("m_Socket == null");
            this.Disconnect();
            return;
        }

        try
        {
            int receiveCount = m_Socket.EndReceive(result);
            if (receiveCount == 0) // 连接已关闭
            {
                GameDebug.Log($"{this.GetHashCode()} 收到关闭信号");
                this.Disconnect();
            }
            else
            {
                //GameDebug.Log($"收到数据长度：{receiveCount}");

                ReceivedData(receiveCount);
                
                BeginReceive();
            }

        }
        catch (Exception ex)
        {
            LogSocketException(ex);

            this.Disconnect();
        }

    }
     void  ReceivedData(int receiveCount)
    {
        if(m_Socket == null)
        {
            GameDebug.LogError("m_Socket == null");
            return;
        }

        byte[] newData = new byte[receiveCount];

        Array.Copy(m_Buffer, newData, receiveCount);

        if (receiveCount > 1)
        {
            //GameDebug.Log($"ReceiveData  decoder != null:{this.decoder != null}");
            List<byte[]> toProcessData = TryGetMessageWithReceiveData(newData);

            if (toProcessData != null)
            {
                toProcessData.ForEach(e =>
              {
                  this.tcpServerListener?.OnReceiveData(m_Socket.RemoteEndPoint, e);
              });
            }
        }
        else
        {
            this.tcpServerListener?.OnReceiveData(m_Socket.RemoteEndPoint, newData);
        }

    }

    //async Task ReceivedData(int receiveCount)
    //{
    //    await Task.Run(() =>
    //   {
    //       byte[] newData = new byte[receiveCount];

    //       Array.Copy(m_Buffer, newData, receiveCount);

    //       if (receiveCount > 1)
    //       {
    //           List<byte[]> toProcessData = TryGetMessageWithReceiveData(newData);

    //           lock (tcpServerListener)
    //           {
    //               toProcessData.ForEach(e =>
    //               {
    //                   this.tcpServerListener?.OnReceiveData(m_Socket.RemoteEndPoint, e);
    //               });
    //           }
    //       }
    //       else
    //       {
    //           lock (tcpServerListener)
    //           {
    //               this.tcpServerListener?.OnReceiveData(m_Socket.RemoteEndPoint, newData);
    //           }
    //       }
    //   });
       
    //}

    //private List<TCPPacket> m_TCPPackets = new List<TCPPacket>();

    //protected override List<byte[]> TryGetMessageWithReceiveData(byte[] newData)
    //{
    //    List<byte[]> res = new List<byte[]>();

    //    int id = BitConverter.ToInt32(newData, 0);

    //    TCPPacket packet = m_TCPPackets.Find(e => e.id == id);
    //    if (packet == null)
    //    {
    //        TCPPacket newPacket = new TCPPacket(id);

    //        newPacket.OnReceivePacket(newData);

    //        if (newPacket.receiveEnd)
    //        {
    //            //GameDebug.Log($"新包处理数据：{newPacket.contentLength}");
    //            res.Add(newPacket.data);
    //        }
    //        else
    //        {
    //            m_TCPPackets.Add(newPacket);
    //        }
    //    }
    //    else
    //    {
    //        packet.OnReceivePacket(newData);

    //        if (packet.receiveEnd)
    //        {
    //            res.Add(packet.data);
    //           // GameDebug.LogError($"接收包完成");
    //            m_TCPPackets.Remove(packet);
    //        }
    //    }

    //    return res;
    //}


    const int maxLengthSendATime = TCPPacket.maxSendContentLengthOneTime;

    private int m_Seq;
    protected int GetCurSeqId()
    {
        return System.Threading.Interlocked.Increment(ref m_Seq);
    }
    /// <summary>
    /// 发送数据
    /// </summary>
    /// <param name="client"></param>
    /// <param name="packet"></param>
    //public override void SendPacket(byte[] packet, EndPoint endPoint)
    //{
    //    int packetId = GetCurSeqId();

    //    byte[] bytes = new byte[packet.Length];
    //    System.Array.Copy(packet, bytes, packet.Length);

    //    Queue<byte[]> m_SendQueue = new Queue<byte[]>();

    //    int index = 0;
    //    while (bytes.Length > maxLengthSendATime)
    //    {
    //        byte[] block = new byte[maxLengthSendATime];
    //        Array.Copy(bytes, block, maxLengthSendATime);

    //        m_SendQueue.Enqueue(block);

    //        index += maxLengthSendATime;

    //        bytes = new byte[bytes.Length - maxLengthSendATime];
    //        Array.Copy(packet, index, bytes, 0, bytes.Length);
    //    }

    //    m_SendQueue.Enqueue(bytes);

    //    int sendIndex = 0;
    //    while (m_SendQueue.Count > 0)
    //    {
    //        byte[] sendData = m_SendQueue.Dequeue();

    //        byte[] headBytes = BitConverter.GetBytes(packetId);
    //        byte[] indexBytes = BitConverter.GetBytes(sendIndex);

    //        string tail = "----";
    //        byte[] tailBytes = System.Text.Encoding.UTF8.GetBytes(tail);
            
    //        int dataLength = sendData.Length;
    //        int headCount = headBytes.Length;
    //        int indexCount = indexBytes.Length;
    //        int tailCount = tailBytes.Length;

    //        if (m_SendQueue.Count == 0)
    //        {
    //            tail = UDPPacket.Tail;
    //            tailBytes = System.Text.Encoding.UTF8.GetBytes(tail);

    //            //GameDebug.Log($"发送尾包");
    //        }

    //        byte[] data = new byte[headCount + dataLength + indexCount + tailCount];

    //        System.Array.Copy(headBytes, 0, data, 0, headCount);
    //        System.Array.Copy(indexBytes, 0, data, headCount, indexCount);
    //        System.Array.Copy(sendData, 0, data, headCount + indexCount, dataLength);
    //        System.Array.Copy(tailBytes, 0, data, headCount + indexCount + dataLength, tailCount);

    //        GameDebug.LogError($"发送 sendIndex:{sendIndex} total:{data.Length} packetHeadCount:{headCount}  indexCount:{indexCount}  dataLength:{dataLength}  tailCount：{tailCount}  endPoint:{endPoint}  ");

    //        this._SendData(data, endPoint);

    //        Thread.Sleep(15);

    //        sendIndex++;
    //    }
    //}

    public override void _SendData(byte[] data,EndPoint endPoint)
    {
        if (m_Socket == null || !m_Socket.Connected)
        {
            GameDebug.Log($"TCP _SendData m_Socket == null：{m_Socket == null}");
            this.Disconnect();
            return;
        }
        try
        {
            m_Socket.Send(data);
        }
        catch (Exception e)
        {
            this.Disconnect();

            LogSocketException(e);
        }
        
    }


    protected override void Disconnect()
    {
        this.tcpServerListener?.OnRecOrSendFailed(this.ipEndPoint);

        if (m_Socket != null)
        {
            Socket s = m_Socket;
            m_Socket = null;
            try
            {
                GameDebug.Log($"关闭Socket：{s?.GetHashCode()}");
                if(s.Connected)
                    s.Shutdown(SocketShutdown.Both);
                s.Close();
            }
            catch (Exception e)
            {
                LogSocketException(e);
            }
        }
        lock (_packetBaton)
        {
            m_Packet = null;
        }
    }

    public void TestDisconnect()
    {
        Disconnect();
    }
}

